/**
 * @fileoverview
 * This script defines a widget for interacting with expression data from flyatlas.
 * @author <a href="http://purl.org/net/aliman">Alistair Miles</a>
 * @version $Revision:538 $ on $Date: 2008-08-27 09:08:41 +0100 (Wed, 27 Aug 2008) $ by $Author: aliman $
 * @requires flyui.util
 * @requires flyui.sparql.Service
 * @requires flyui.flyatlas.Service
 * @requires YAHOO.util.Connect
 * @requires jQuery
 * For license terms see http://flyui.googlecode.com
 */
 
flyui.namespace("flyui.flyatlas");
 
 
 
 
 

/*
 * ----------------------------------------------------------------
 *                             WIDGET
 * ----------------------------------------------------------------
 */







flyui.flyatlas.BatchWidget = function( service, renderer ) {
    var _context = "flyui.flyatlas.BatchWidget";
    try {
        
        flyui.debug("call private constructor", _context);
        this.__init__(service, renderer);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
    
}



 
 



/** @private */
flyui.flyatlas.BatchWidget.prototype._controller = null;

/**
 * @private
 * @type flyui.mvcutils.GenericModel2
 */ 
flyui.flyatlas.BatchWidget.prototype._model = null;

/**
 * @private
 */
flyui.flyatlas.BatchWidget.prototype._renderer = null;

/**
 * @private
 */
flyui.flyatlas.BatchWidget.prototype._service = null;










/**
 * @private
 */
flyui.flyatlas.BatchWidget.prototype.__init__ = function( service, renderer ) {
    var _context = "flyui.flyatlas.BatchWidget.prototype.__init__";
    try {
        
        this._service = service;
        this._renderer = renderer;
        
        flyui.debug("create a model", _context);
        this._model = new flyui.mvcutils.GenericModel2();
        this._model.setDefinition(flyui.flyatlas.BatchWidget.modelDefinition);
        
        flyui.debug("create a controller", _context);
        this._controller = new flyui.flyatlas.BatchWidget.Controller(this._model, service, this);
        
        flyui.debug("connect the renderer to the model", _context);
        this._renderer.connect(this._model);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/**
 * @public
 * @param {Array<String>} querynames
 * @param {Array<String>} flybaseids
 */
flyui.flyatlas.BatchWidget.prototype.getAssaysByGeneBatch = function( querynames, flybaseids ) {
    var _context = "flyui.flyatlas.BatchWidget.prototype.getAssaysByGeneBatch";
    try {
        
        flyui.debug("pass ["+querynames+"], ["+flybaseids+"] through to controller", _context);
        this._controller.getAssaysByGeneBatch(querynames, flybaseids);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/*
 * ----------------------------------------------------------------
 *                             CONTROLLER
 * ----------------------------------------------------------------
 */






/**
 * @class
 */
flyui.flyatlas.BatchWidget.Controller = function( model, service, controllee ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller";
    try {
        
        this._model = null;
        this._service = null;
        this._controllee = null;
        
        flyui.debug("call private constructor", _context);
        this.__init__(model, service, controllee);        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype.__init__ = function( model, service, controllee ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype.__init__";
    try {
        
        this._model = model;
        this._service = service;
        this._controllee = controllee;
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @public
 */
flyui.flyatlas.BatchWidget.Controller.prototype.getAssaysByGeneBatch = function( querynames, flybaseids ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype.findGenesByAnyNameBatch";
    try {
        
        flyui.info("getAssaysByGeneBatch: "+querynames+" || "+flybaseids, _context);
        flyui.debug("pass through to private implementation", _context);
        this._getAssaysByGeneBatch(querynames, flybaseids, this._getAssaysByGeneBatchSuccess(), this._getAssaysByGeneBatchFailure());
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatch = function( querynames, flybaseids, success, failure ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatch";
    try {
        
        flyui.debug("querynames: "+querynames, _context);
        flyui.debug("flybaseids: "+flybaseids, _context);
        
        flyui.debug("set state pending", _context);
        this._model.set("STATE", "PENDING");
        
        flyui.debug("set model property query", _context);
        this._model.set("QUERY", [querynames, flybaseids]);

        flyui.debug("set result null", _context);
        this._model.set("RESULTS", null);
                
        flyui.debug("set message null", _context);
        this._model.set("MESSAGE", null);
                
        flyui.debug("kick off request", _context);
        this._service.getAssaysByFlybaseGeneIdBatch(flybaseids, success, failure);        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};









/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchSuccess = function() {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchSuccess";
    var self = this;
    /**
     * @param {Object<String,<Array<AssayGroup>>} results a map from flybaseids to arrays of AssayGroup objects
     */
    return function( results ) {
        try {
            
            flyui.info("request success", _context);
            
            flyui.debug("set model results", _context);
            self._model.set("RESULTS", results);
            
            flyui.debug("set model state", _context);
            self._model.set("STATE", "READY");
            
            var explanation = "Values shown are mean mRNA signal plus or minus standard error on the mean; cell background colour indicates results of T-test comparison with whole fly, green is up, red is down, white is no change. Empty cells indicate no data are available for that gene. See also: Chintapalli, V. R., Wang, J. and Dow, J. A. T. (2007) Using FlyAtlas to identify better Drosophila models of human disease, <a href='http://www.nature.com/ng/journal/v39/n6/abs/ng2049.html'>Nature Genetics 39: 715-720</a>.";
            self._model.set("MESSAGE", explanation);
            
        } catch (unexpected) {
            flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
            throw unexpected;    
        }
    };
};







/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchFailure = function() {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchFailure";
    var self = this;
    /**
     * @param {ResponseObject} response
     */
    return function( response ) {
        try {
            
            flyui.err("request failed: "+response.status+" "+response.statusText, _context);
            self._model.set("MESSAGE", "there was an error retrieving data from the server, see the logs for more info");
            self._model.set("STATE", "SERVERERROR");
            
        } catch (unexpected) {
            flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
            throw unexpected;    
        }
    };
};







/*
 * ----------------------------------------------------------------
 *                             MODEL DEFINITION
 * ----------------------------------------------------------------
 */





/** 
 * @type Object
 */
flyui.flyatlas.BatchWidget.modelDefinition = {

    properties : [ "STATE", "RESULTS", "MESSAGE", "QUERY" ],
    
    values : {
        "STATE" : [ "READY", "PENDING", "SERVERERROR", "UNEXPECTEDERROR" ]
    },
    
    initialize : function( data ) {
        data["STATE"] = "READY";
        data["RESULTS"] = null;
        data["MESSAGE"] = null;
        data["QUERY"] = null;
    }

};







/*
 * ----------------------------------------------------------------
 *                             DEFAULT RENDERER
 * ----------------------------------------------------------------
 */







flyui.flyatlas.BatchWidget.DefaultRenderer = function() {};


/** 
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._canvas = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._pendingPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._resultsSummaryPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._resultsPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._messagePane = null;





/**
 * Set the DOM element to which this renderer applies and initialise it.
 * @param {Element} canvas
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.setCanvas = function( canvas ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.setCanvas";
    try {
        
        flyui.debug("set canvas", _context);
        this._canvas = $(canvas);
        this._initCanvas();
        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 * @param {Element} canvas
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._initCanvas = function() {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._initCanvas";
    try {
        
        flyui.debug("begin init canvas", _context);
        
        var canvas = this._canvas;
        canvas.addClass("batchFlyatlasWidget");

        var pp = $("<p class='pendingPane'>pending (please wait, this can take up to 10 seconds) ...</p>").hide();
        canvas.append(pp);
        this._pendingPane = pp;

        var rsp = $("<p class='resultsSummaryPane'>this text should never be displayed</p>").hide();
        canvas.append(rsp);
        this._resultsSummaryPane = rsp;
        
        var rp = $("<div class='resultsPane'></div>").hide();
        canvas.append(rp);
        this._resultsPane = rp;
        
        var mp = $("<p class='messagePane'>this text should never be displayed</p>").hide();
        canvas.append(mp);
        this._messagePane = mp;            

        flyui.debug("init canvas done", _context);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





/**
 * @public
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.connect = function( model ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.connect";
    try {
        
        flyui.debug("connect to model", _context);
        model.subscribeAll(this._onModelChanged, this);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onModelChanged = function( type, args, self ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onModelChanged";
    try {
        
        var handlers = {
            "STATE":"_onStateChanged",
            "QUERY":"_onQueryChanged",
            "RESULTS":"_onResultsChanged",
            "MESSAGE":"_onMessageChanged"
        };
        var handler = handlers[type];
        flyui.debug("call model changed handler: "+handler, _context);
        self[handler](args[0], args[1], args[2]);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onQueryChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onQueryChanged";
    try {
        
        // do nothing, we will access the value later
        flyui.debug("query changed from "+from+" to "+to, _context);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onStateChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onStateChanged";
    try {
        
        flyui.debug("state changed from "+from+" to "+to, _context);

        if ( to == "PENDING" ) {
            this._pendingPane.show();
            this._messagePane.hide();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();
        }
        else if ( to == "READY" ) {
            this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.show();
            this._resultsPane.show();         
        } 
        else if ( to == "SERVERERROR" || to == "UNEXPECTEDERROR" ) {
            this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();         
        } 
        else {
            // this should never happen
            throw {message:"invalid state: "+to};
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onResultsChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onResultsChanged";
    try {
        
        flyui.debug("results changed to: "+to, _context);
        
        if (to == null) {
            flyui.debug("empty results summary pane", _context);
            this._resultsSummaryPane.empty();
            flyui.debug("empty results pane", _context);
            this._resultsPane.empty();
        } 
        
        else {

            var query = get("QUERY");
            
            flyui.debug("render results summary", _context);
            this._renderResultsSummary(query, to);
    
            flyui.debug("render results", _context);
            this._renderResults(query, to);        
            
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onMessageChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onMessageChanged";
    try {
        
        flyui.debug("message changed to: "+to, _context);
        
        if (to == null) {
            flyui.debug("empty messsage pane", _context);
            this._messagePane.empty();
        } 
        
        else {

            this._messagePane.html(to);
            
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};









/**
 * @private
 * @param {Object<String,<Array<AssayGroup>>} results a map from flybaseids to arrays of assay group objects
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResultsSummary = function( query, results ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResultsSummary";
    try {
        
        flyui.debug("render results summary", _context);

        var querynames = query[0];
        var flybaseids = query[1];
        
        var content = "";
        var count = 0;        
        for (var i=0;i<querynames.length;i++) {
//            content += "probes for "+querynames[i] + " ("+flybaseids[i]+"): ";
            var groups = results[flybaseids[i]];
            count += groups.length;
//            if (groups.length == 0) {
//                content += "no matching probes; ";
//            }
//            else {
//                for (var j=0;j<groups.length;j++) {
//                    content += "<a href='http://flyatlas.org/probeset.cgi?name="+groups[j].affy_id+"'>"+groups[j].affy_id+"</a>" + " ";
//                }
//            }
//            content += "<br/>";
        }
        
        var content = "found ";
        content += count;
        content += " matching probe";
        content += (count == 0 || count > 1) ? "s " : " ";
        content += "from <a href='http://flyatlas.org'>flyatlas.org</a> (data obtained on 2008-09-16) ...";

        this._resultsSummaryPane.html(content);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 * @param {Object<String,<Array<Gene>>} results a map from names in the query to arrays of gene objects
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResults = function( query, results ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResults";
    try {
        flyui.debug("render results", _context);

        var querynames = query[0];
        var flybaseids = query[1];
        
        var content = "<table><thead><tr><th>gene</th><th>probe</th>";
        for (var i=0;i<flyui.flyatlas.tissues.length;i++) {
            var tissue = flyui.flyatlas.tissues[i];
            content += "<th>" + tissue + "</th>";
        }
        content += "</tr></thead>"
        
        for (var i=0;i<querynames.length;i++) {
            var n = querynames[i];
            var id = flybaseids[i];
            var groups = results[id];
            content += "<tbody>";
            if (groups.length > 0) {
                for (var j=0; j<groups.length;j++) {
                    content += "<tr>";
//                    if (j == 0 && groups.length > 1) {
//                        content += "<td rowspan='"+groups.length+"'>" + n + "</td>";
//                    }
//                    else if (j == 0) {
//                        content += "<td>" + n + "</td>";                        
//                    }
                    content += "<td>" + n + "</td>";                        
                    var group = groups[j];
                    content += "<td>" + "<a href='http://flyatlas.org/probeset.cgi?name="+group.affy_id+"'>"+group.affy_id+"</a>" + "</td>";
                    for (var k=0;k<flyui.flyatlas.tissues.length;k++) {
                        var tissue = flyui.flyatlas.tissues[k];
                        var change = group[tissue].change;
                        var mean = group[tissue].mean;
                        var sem = group[tissue].sem;
                        var clsname = "flyatlasChangeNone";
                        if (change == "Up") {
                            clsname = "flyatlasChangeUp";
                        }
                        else if (change == "Down") {
                            clsname = "flyatlasChangeDown";
                        }
                        content += "<td class='"+clsname+"'>" + mean + "±" +sem + "</td>";
                    }
                    content += "</tr>";
                }
            }
            else {
                content += "<tr><td>" + n + "</td></tr>";
            }
            content += "</tbody>";    
        }
        
        
        content += "</table>";
        this._resultsPane.html(content);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





















